package com.ruoyi.learn.java.design.pattern.struct;

/**
 * 外观模式 (Facade Pattern) 示例：简化家庭影院系统的操作。
 */
/**
 * 外观模式 (Facade Pattern) 示例：简化家庭影院系统的操作。
 */
public class FacadePatternDemo {

    //region ========== 1. 子系统 (Subsystems) ==========

    /**
     * 子系统：投影仪
     */
    public static class Projector {
        public void on() {
            System.out.println("    > 投影仪: 开启");
        }

        public void off() {
            System.out.println("    > 投影仪: 关闭");
        }

        public void setInput(DvdPlayer dvd) {
            System.out.println("    > 投影仪: 设置输入源为 DVD 播放器");
        }

        public void focus() {
            System.out.println("    > 投影仪: 聚焦画面");
        }
    }

    /**
     * 子系统：屏幕
     */
    public static class Screen {
        public void down() {
            System.out.println("    > 电动屏幕: 放下");
        }

        public void up() {
            System.out.println("    > 电动屏幕: 升起");
        }
    }

    /**
     * 子系统：音响系统 (立体声)
     */
    public static class Stereo {
        public void on() {
            System.out.println("    > 音响系统: 开启");
        }

        public void off() {
            System.out.println("    > 音响系统: 关闭");
        }

        public void setDvd() {
            System.out.println("    > 音响系统: 设置音源为 DVD");
        }

        public void setVolume(int level) {
            System.out.println("    > 音响系统: 音量调至 " + level);
        }
    }

    /**
     * 子系统：DVD 播放器
     */
    public static class DvdPlayer {
        public void on() {
            System.out.println("    > DVD 播放器: 开启");
        }

        public void off() {
            System.out.println("    > DVD 播放器: 关闭");
        }

        public void eject() {
            System.out.println("    > DVD 播放器: 弹出光盘");
        }

        public void play(String movie) {
            System.out.println("    > DVD 播放器: 正在播放 '" + movie + "'");
        }
    }

    /**
     * 子系统：灯光系统
     */
    public static class TheaterLights {
        public void dim(int level) {
            System.out.println("    > 观影灯: 调暗至 " + level + "%");
        }

        public void on() {
            System.out.println("    > 观影灯: 打开");
        }
    }

    //endregion

    //region ========== 2. 外观 (Facade) ==========

    /**
     * 外观：家庭影院外观
     * 封装了所有子系统的复杂操作，提供简单的高级接口。
     */
    public static class HomeTheaterFacade {
        private Projector projector;
        private Screen screen;
        private Stereo stereo;
        private DvdPlayer dvd;
        private TheaterLights lights;

        // 构造函数中初始化所有子系统组件
        public HomeTheaterFacade(Projector projector, Screen screen,
                                 Stereo stereo, DvdPlayer dvd, TheaterLights lights) {
            this.projector = projector;
            this.screen = screen;
            this.stereo = stereo;
            this.dvd = dvd;
            this.lights = lights;
        }

        /**
         * 一键开启观影模式
         * 将复杂的启动步骤封装在一个方法中。
         * @param movie 要观看的电影名称
         */
        public void watchMovie(String movie) {
            System.out.println("【外观】准备开始观影...");
            lights.dim(10);
            screen.down();
            projector.on();
            projector.setInput(dvd);
            projector.focus();
            stereo.on();
            stereo.setDvd();
            stereo.setVolume(5);
            dvd.on();
            dvd.play(movie);
            System.out.println("【外观】观影模式已就绪，享受电影吧！");
        }

        /**
         * 一键结束观影模式
         * 将复杂的关闭步骤封装在一个方法中。
         */
        public void endMovie() {
            System.out.println("【外观】电影结束，正在关闭系统...");
            dvd.eject();
            dvd.off();
            projector.off();
            stereo.off();
            screen.up();
            lights.on();
            System.out.println("【外观】家庭影院系统已关闭。");
        }
    }

    //endregion

    //region ========== 3. 客户端 (Client) ==========

    /**
     * 家庭影院用户
     * 只需要知道外观类，无需了解内部设备的复杂操作。
     */
    public static class HomeUser {
        private HomeTheaterFacade facade;

        public HomeUser(HomeTheaterFacade facade) {
            this.facade = facade;
        }

        public void startWatching() {
            System.out.println("【用户】按下遥控器上的 '观影' 按钮。");
            facade.watchMovie("阿凡达");
        }

        public void stopWatching() {
            System.out.println("【用户】按下遥控器上的 '结束' 按钮。");
            facade.endMovie();
        }
    }

    //endregion

    //region ========== 4. 主函数 (Main) - 演示外观模式 ==========

    public static void main(String[] args) {
        System.out.println("=== 外观模式演示 ===\n");

        // 1. 初始化所有子系统组件
        System.out.println("1. 初始化家庭影院子系统...");
        Projector projector = new Projector();
        Screen screen = new Screen();
        Stereo stereo = new Stereo();
        DvdPlayer dvd = new DvdPlayer();
        TheaterLights lights = new TheaterLights();

        // 2. 创建外观对象，将所有子系统组件注入
        System.out.println("2. 创建家庭影院外观...");
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(projector, screen, stereo, dvd, lights);

        // 3. 创建用户，并传入外观
        System.out.println("3. 用户准备就绪。\n");
        HomeUser user = new HomeUser(homeTheater);

        // 4. 用户使用外观的一键功能
        user.startWatching();
        System.out.println(); // 空行分隔
        user.stopWatching();

        // 5. 对比：如果用户直接操作子系统（不推荐，非常繁琐）
        System.out.println("\n--- 对比：不使用外观模式 ---");
        System.out.println("如果用户需要直接操作所有设备：");
        // 模拟用户需要手动执行所有步骤
        System.out.println("用户需要：");
        System.out.println("  1. 调暗灯光至 10%");
        System.out.println("  2. 放下屏幕");
        System.out.println("  3. 开启投影仪");
        System.out.println("  4. 设置投影仪输入源为 DVD");
        System.out.println("  5. 聚焦投影仪");
        System.out.println("  6. 开启音响系统");
        System.out.println("  7. 设置音响音源为 DVD");
        System.out.println("  8. 调节音响音量");
        System.out.println("  9. 开启 DVD 播放器");
        System.out.println("  10. 播放电影");
        System.out.println("结束时又需要反向执行一系列关闭操作...");
        System.out.println("使用外观模式大大简化了操作！");

        // 6. 演示外观模式的灵活性
        System.out.println("\n--- 演示：外观模式的灵活性 ---");
        // 假设我们想添加一个新的功能，比如“浪漫模式”，只需在外观类中添加方法，不影响客户端现有代码。
        // (这里不修改代码，仅说明概念)
        System.out.println("未来可以轻松在 HomeTheaterFacade 中添加 'romanticMode()' 方法，");
        System.out.println("用户只需调用 facade.romanticMode() 即可，无需了解内部细节。");
    }

    //endregion
}